package com.easychat.service.impl;

import com.easychat.ai.OllamaChatService;
import com.easychat.common.LeaseException;
import com.easychat.dto.MessageSendDto;
import com.easychat.dto.SysSettingDto;
import com.easychat.dto.TokenUserInfoDto;
import com.easychat.entity.ChatMessage;
import com.easychat.entity.ChatSession;
import com.easychat.entity.ChatSessionUser;
import com.easychat.entity.UserContact;
import com.easychat.entity.config.AppConfig;
import com.easychat.entity.constants.Constants;
import com.easychat.entity.query.ChatMessageQuery;
import com.easychat.enums.*;
import com.easychat.mappers.ChatMessageDao;
import com.easychat.mappers.ChatSessionDao;
import com.easychat.mappers.ChatSessionUserDao;
import com.easychat.mappers.UserContactDao;
import com.easychat.redis.RedisComponent;
import com.easychat.service.ChatMessageService;
import com.easychat.utils.StringTools;
import com.easychat.websocket.MessageHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.rmi.dgc.Lease;
import java.util.Date;
import java.util.List;

/**
 * (ChatMessage)表服务实现类
 *
 * @author makejava
 * @since 2024-10-19 22:24:24
 */
@Slf4j
@Service("chatMessageService")
public class ChatMessageServiceImpl implements ChatMessageService {
    @Resource
    private ChatMessageDao chatMessageDao;
    @Resource
    private RedisComponent redisComponent;
    @Resource
    private ChatSessionDao chatSessionDao;
    @Resource
    private MessageHandler messageHandler;
    @Resource
    private AppConfig appConfig;
    @Resource
    private UserContactDao userContactDao;
    @Resource
    private OllamaChatService ollamaChatService;

    /**
     * 通过ID查询单条数据
     *
     * @param messageId 主键
     * @return 实例对象
     */
    @Override
    public ChatMessage queryById(Long messageId) {
        return this.chatMessageDao.queryById(messageId);
    }

    /**
     * 分页查询
     *
     * @param chatMessage 筛选条件
     * @param pageRequest      分页对象
     * @return 查询结果
     */
    @Override
    public Page<ChatMessage> queryByPage(ChatMessage chatMessage, PageRequest pageRequest) {
        long total = this.chatMessageDao.count(chatMessage);
        return new PageImpl<>(this.chatMessageDao.queryAllByLimit(chatMessage, pageRequest), pageRequest, total);
    }

    /**
     * 新增数据
     *
     * @param chatMessage 实例对象
     * @return 实例对象
     */
    @Override
    public ChatMessage insert(ChatMessage chatMessage) {
        this.chatMessageDao.insert(chatMessage);
        return chatMessage;
    }

    /**
     * 修改数据
     *
     * @param chatMessage 实例对象
     * @return 实例对象
     */
    @Override
    public ChatMessage update(ChatMessage chatMessage) {
        this.chatMessageDao.update(chatMessage);
        return this.queryById(chatMessage.getMessageId());
    }

    /**
     * 通过主键删除数据
     *
     * @param messageId 主键
     * @return 是否成功
     */
    @Override
    public boolean deleteById(Long messageId) {
        return this.chatMessageDao.deleteById(messageId) > 0;
    }

    @Override
    public MessageSendDto saveMessage(ChatMessage chatMessage, TokenUserInfoDto tokenUserInfoDto) {
        //不是机器人回复，判断好友状态
        if(!Constants.ROBOT_UID.equals(tokenUserInfoDto.getUserId())){
            List<String> userContactList = redisComponent.getUserContactList(tokenUserInfoDto.getUserId());
            if(!userContactList.contains(chatMessage.getContactId())){
                UserContactTypeEnum typeEnum = UserContactTypeEnum.getByPrefix(chatMessage.getContactId());
                if(UserContactTypeEnum.USER==typeEnum){
                    throw new LeaseException("您不是对方好友，是否发起好友申请");
                }else {
                    throw new LeaseException("请先加入群聊，才能发送消息");
                }
            }
        }
        String sessionId = null;
        String sendUserId = tokenUserInfoDto.getUserId();
        String contactId = chatMessage.getContactId();
        long curTime = System.currentTimeMillis();
        UserContactTypeEnum contactTypeEnum = UserContactTypeEnum.getByPrefix(contactId);
        if(UserContactTypeEnum.USER==contactTypeEnum){
            sessionId = StringTools.getChatSessionId4User(new String[]{sendUserId,contactId});
        }else {
            sessionId = StringTools.getChatSessionId4Group(contactId);
        }
        MessageTypeEnum messageTypeEnum = MessageTypeEnum.getByType(chatMessage.getMessageType());
        if(null == messageTypeEnum || !ArrayUtils.contains(new Integer[]{MessageTypeEnum.CHAT.getType(),MessageTypeEnum.MEDIA_CHAT.getType()},messageTypeEnum.getType())){
            throw new LeaseException(ExceptionCodeEnum.ERROR_REQUEST);
        }
        chatMessage.setSendTime(curTime);

        Integer status = MessageTypeEnum.MEDIA_CHAT==messageTypeEnum? MessageStatusEnum.SENDING.getStatus() : MessageStatusEnum.SENDED.getStatus();
        chatMessage.setStatus(status);
        String messageContent = StringTools.cleanHtmlTag(chatMessage.getMessageContent());
        chatMessage.setMessageContent(messageContent);

        //更新会话
        ChatSession chatSession = new ChatSession();
        chatSession.setSessionId(sessionId);
        if(UserContactTypeEnum.GROUP==contactTypeEnum){
            chatSession.setLastMessage(tokenUserInfoDto.getNickName()+"："+messageContent);
        }
        chatSession.setLastReceiveTime(curTime);
        chatSessionDao.update(chatSession);

        //记录消息表
        chatMessage.setSendUserId(sendUserId);
        chatMessage.setSendUserNickName(tokenUserInfoDto.getNickName());
        chatMessage.setContactType(contactTypeEnum.getType());
        chatMessage.setSessionId(sessionId);

        chatMessageDao.insert(chatMessage);

        MessageSendDto messageSendDto = new MessageSendDto();
        BeanUtils.copyProperties(chatMessage,messageSendDto);
        if(Constants.ROBOT_UID.equals(contactId)){ //Urobot
            SysSettingDto sysSetting = redisComponent.getSysSetting();
            TokenUserInfoDto robot = new TokenUserInfoDto();
            robot.setUserId(sysSetting.getRobotUid());
            robot.setNickName(sysSetting.getRobotNickName());
            ChatMessage robotChatMessage = new ChatMessage();
            robotChatMessage.setContactId(sendUserId);
            //调用ai，实现聊天
            log.info("开始调用ai聊天，发送消息：{}",messageContent);
            String chatRes = ollamaChatService.chat(messageContent);

            robotChatMessage.setMessageContent(chatRes);
            robotChatMessage.setMessageType(MessageTypeEnum.CHAT.getType());
            saveMessage(robotChatMessage,robot);
        }else {
            messageHandler.sendMessage(messageSendDto);
        }

        return messageSendDto;
    }

    @Override
    public void saveMessageFile(String userId, Long messageId, MultipartFile file, MultipartFile cover) {
        ChatMessage chatMessage = chatMessageDao.queryById(messageId);
        if(chatMessage== null){
            throw new LeaseException(ExceptionCodeEnum.ERROR_REQUEST);
        }
        if(chatMessage.getSendUserId().equals(userId)){
            throw new LeaseException(ExceptionCodeEnum.ERROR_REQUEST);
        }
        SysSettingDto sysSetting = redisComponent.getSysSetting();
        String fileSuffix = StringTools.getFileSuffix(file.getOriginalFilename());
        if(!StringTools.isEmpty(fileSuffix)
                && ArrayUtils.contains(Constants.IMAGE_SUFFIX_LIST,fileSuffix.toUpperCase())
                && file.getSize() > sysSetting.getMaxImageSize()*Constants.FILE_SIZE_MB){
                throw new LeaseException(ExceptionCodeEnum.ERROR_REQUEST);
        }else if (!StringTools.isEmpty(fileSuffix)
                && ArrayUtils.contains(Constants.VIDEO_SUFFIX_LIST,fileSuffix.toUpperCase())
                && file.getSize() > sysSetting.getMaxVideoSize()*Constants.FILE_SIZE_MB){

        }else if(!StringTools.isEmpty(fileSuffix)
                && !ArrayUtils.contains(Constants.VIDEO_SUFFIX_LIST,fileSuffix.toUpperCase())
                && !ArrayUtils.contains(Constants.IMAGE_SUFFIX_LIST,fileSuffix.toUpperCase())
                && file.getSize() > sysSetting.getMaxVideoSize()*Constants.FILE_SIZE_MB){
                throw new LeaseException(ExceptionCodeEnum.ERROR_REQUEST);
        }
        String fileName = file.getOriginalFilename();
        String fileExtName = StringTools.getFileSuffix(fileName);
        String fileRealName = messageId+fileExtName;
        //将不同文件按时间年/月来进行分放
        Date date = new Date(chatMessage.getSendTime());
        String month = DateFormatUtils.format(date, "yyyyMM");
        File folder = new File(appConfig.getProjectFolder() + Constants.FILE_FOLDER_FILE + month);
        if(!folder.exists()){
            folder.mkdirs();
        }
        File uploadFile = new File(folder.getPath()+"/"+fileRealName);
        try{
            file.transferTo(uploadFile);
            cover.transferTo(new File(uploadFile.getPath()+Constants.COVER_IMAGE_SUFFIX));
        }catch (IOException e){
            log.error("上传文件失败",e);
            throw new LeaseException("上传文件失败");
        }
        chatMessage.setStatus(MessageStatusEnum.SENDED.getStatus());
        chatMessage.setMessageId(messageId);
        chatMessageDao.update(chatMessage);

        MessageSendDto messageSendDto = new MessageSendDto();
        messageSendDto.setStatus(MessageStatusEnum.SENDED.getStatus());
        messageSendDto.setMessageId(messageId);
        messageSendDto.setMessageType(MessageTypeEnum.FILE_UPLOAD.getType());
        messageSendDto.setContactId(chatMessage.getContactId());
        messageHandler.sendMessage(messageSendDto);

    }

    @Override
    public File downloadFile(TokenUserInfoDto tokenUserInfoDto, Long messageId, Boolean showover) {
        ChatMessage chatMessage = chatMessageDao.queryById(messageId);
        String contactId = chatMessage.getContactId();
        UserContactTypeEnum contactTypeEnum = UserContactTypeEnum.getByPrefix(contactId);
        if(UserContactTypeEnum.USER == contactTypeEnum&& !tokenUserInfoDto.getUserId().equals(chatMessage.getContactId())){
            throw new LeaseException(ExceptionCodeEnum.ERROR_REQUEST);
        }
        if(UserContactTypeEnum.GROUP == contactTypeEnum){
            UserContact userContact = new UserContact();
            userContact.setUserId(tokenUserInfoDto.getUserId());
            userContact.setContactType(UserContactTypeEnum.GROUP.getType());
            userContact.setContactId(contactId);
            userContact.setStatus(UserContactStatusEnum.FRIEND.getStatus());
            Long contactCount = userContactDao.count(userContact);
            if(contactCount==0){
                throw new LeaseException(ExceptionCodeEnum.ERROR_REQUEST);
            }
        }
        String month = DateFormatUtils.format(new Date(chatMessage.getSendTime()),"YYYYMM");
        File folder = new File(appConfig.getProjectFolder() + Constants.FILE_FOLDER_FILE + month);
        if(!folder.exists()){
            folder.mkdirs();
        }
        String fileName = chatMessage.getFileName();
        String fileExtName = StringTools.getFileSuffix(fileName);
        String fileRealName = messageId + fileExtName;

        if(showover!=null &&showover){
            fileRealName = fileRealName + Constants.COVER_IMAGE_SUFFIX;
        }
        File file = new File(folder.getPath() + "/" + fileRealName);
        if(!file.exists()){
            log.info("文件不存在{}",messageId);
            throw new LeaseException(ExceptionCodeEnum.IMAGE_NOT_EXIST);
        }
        return file;
    }
}
